﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace ConsoleUtility.Command
{
    /// <summary>
    /// 解析和执行命令
    /// </summary>
    public class CommandExcuter
    {
        private Queue<string> queue; //输入队列
        private Command command; //命令
        private List<string> parameters; //调用方法实参

        /// <summary>
        /// 命令资源
        /// </summary>
        public object Source { get; set; }

        /// <summary>
        /// 调用方法
        /// </summary>
        public MethodInfo MethodInfo { get; set; }

        /// <summary>
        /// 方法参数
        /// </summary>
        public List<string> Parameters { get { return parameters; } }

        /// <summary>
        /// 初始化
        /// </summary>
        public CommandExcuter()
        {
            queue = new Queue<string>();
            parameters = new List<string>();
        }

        /// <summary>
        /// 执行命令
        /// </summary>
        /// <returns></returns>
        public object Excute()
        {
            if (MethodInfo == null || parameters == null)
                return null;

            try
            {
                return MethodInfo.IsStatic ?
                    MethodInfo.Invoke(null, parameters.ToArray()) :
                    MethodInfo.Invoke(Source, parameters.ToArray());
            }
            catch (Exception e)
            {
                Console.WriteLine("Failed to excute command. " + e.Message);
                return null;
            }
        }

        public bool Parse(string[] input)
        {
            if (input == null || input.Length == 0)
                return false;

            #region 重置

            command = null;
            Source = null;
            MethodInfo = null;

            queue.Clear();
            parameters.Clear();

            #endregion

            foreach (var i in input)
            {
                queue.Enqueue(i);
            }

            return ParseQueue();
        }

        /// <summary>
        /// 解析输入
        /// </summary>
        /// <param name="input">输入</param>
        /// <returns></returns>
        public bool Parse(string input)
        {
            if (string.IsNullOrWhiteSpace(input))
                return false;

            #region 重置

            command = null;
            Source = null;
            MethodInfo = null;

            queue.Clear();
            parameters.Clear();

            #endregion

            var sb = new StringBuilder();

            var searchQuotation = false; //寻找右引号
            var leftQuotation = -1; //左引号索引

            var inputArray = input.ToArray();

            //按引号或空格分段，加入输入队列
            for (int i = 0; i < inputArray.Length; i++)
            {
                var c = inputArray[i];

                if (searchQuotation)
                {
                    if (!c.Equals('"'))
                        continue;

                    queue.Enqueue(input.Substring(leftQuotation + 1, i - leftQuotation - 1));

                    searchQuotation = false;
                    leftQuotation = -1;
                }
                else
                {
                    if (sb.Length == 0 && c.Equals(' '))
                        continue;

                    if (sb.Length == 0 && c.Equals('"'))
                    {
                        searchQuotation = true;
                        leftQuotation = i;

                        continue;
                    }

                    if (!c.Equals(' '))
                    {
                        sb.Append(c);
                    }

                    if (c.Equals(' ') || i == inputArray.Length - 1)
                    {
                        queue.Enqueue(sb.ToString());
                        sb.Clear();
                    }
                }
            }

            return ParseQueue();
        }

        private bool ParseQueue()
        {
            //从输入队列获取命令
            var commandName = queue.Dequeue();
            command = CommandHelper.Commands.FirstOrDefault(c => c.Name == commandName);

            if (command == null)
            {
                Console.WriteLine("Command not found.");
                return false;
            }

            //获取命令资源实例
            if (!command.SourceType.IsAbstract)
            {
                Source = Activator.CreateInstance(command.SourceType);
            }

            //解析参数
            if (!ParseParameter())
                return false;

            return true;
        }

        /// <summary>
        /// 解析参数
        /// </summary>
        /// <returns></returns>
        private bool ParseParameter()
        {
            //直至队列为空
            while (queue.Count > 0)
            {
                //从输入队列获取下一个参数
                var item = queue.Dequeue();

                //分类参数
                if (item.StartsWith("--"))
                {
                    if (item.Length <= 2)
                    {
                        Console.WriteLine("Invalid parameter " + item + ".");
                        return false;
                    }

                    //获取参数值
                    var name = item.Substring(2);

                    //解析参数
                    if (!ParseParameter(item, o => o.Name == name, m => m.Name == name))
                        return false;
                }
                else if (item.StartsWith("-"))
                {
                    if (item.Length <= 1)
                    {
                        Console.WriteLine("Invalid parameter " + item + ".");
                        return false;
                    }

                    //获取参数值集合
                    var chars = item.Substring(1).ToArray();
                    foreach (var cha in chars)
                    {
                        //解析参数
                        if (!ParseParameter(item, o => o.Character == cha, m => m.Character == cha))
                            return false;
                    }
                }
                else
                {
                    //获取调用方法实参
                    parameters.Add(item);
                }
            }

            //如果未解析到调用方法，则获取命令默认方法
            if (MethodInfo == null)
            {
                if (command.DefaultMethod == null)
                {
                    Console.WriteLine("Invalid command.");
                    return false;
                }

                MethodInfo = command.DefaultMethod;
            }

            return true;
        }

        /// <summary>
        /// 解析单个参数
        /// </summary>
        /// <param name="item">参数</param>
        /// <param name="optionPredicate">option筛选方法</param>
        /// <param name="methodPredicate">method筛选方法</param>
        /// <returns></returns>
        private bool ParseParameter(string item, Func<Option, bool> optionPredicate, Func<Method, bool> methodPredicate)
        {
            if (command == null || queue == null || optionPredicate == null || methodPredicate == null)
                return false;

            //获取option
            var option = command.Options.FirstOrDefault(optionPredicate);
            if (option != null)
            {
                //设置option到命令资源
                if (!SetOption(item, option))
                    return false;

                return true;
            }

            if (MethodInfo != null)
            {
                Console.WriteLine("Option " + item + " not found.");
                return false;
            }

            //如果option不存在，获取方法
            var method = command.Methods.FirstOrDefault(methodPredicate);
            if (method == null)
            {
                Console.WriteLine("Invalid parameter " + item + ".");
                return false;
            }

            //设置调用方法
            MethodInfo = method.Info;
            return true;
        }

        /// <summary>
        /// 设置option
        /// </summary>
        /// <param name="item">参数</param>
        /// <param name="option">option</param>
        /// <returns></returns>
        private bool SetOption(string item, Option option)
        {
            if (option == null || queue == null)
                return false;

            //获取属性
            var propertyInfo = option.Info;

            //分类属性
            if (propertyInfo.PropertyType == typeof(bool))
            {
                //设置bool属性
                propertyInfo.SetValue(propertyInfo.SetMethod.IsStatic ? null : Source, true);
            }
            else if (propertyInfo.PropertyType == typeof(string))
            {
                //从输入队列获取下一个参数
                var value = queue.Count > 0 ? queue.Dequeue() : null;
                if (value == null || value.StartsWith("-") || value.StartsWith("--"))
                {
                    Console.WriteLine("Parameter required for " + item + ".");
                    return false;
                }

                //设置string属性
                propertyInfo.SetValue(propertyInfo.SetMethod.IsStatic ? null : Source, value);
            }

            return true;
        }
    }
}
